﻿using Core.Web.Model;
using Core.Framework.Model.Common;
using Core.Framework.Redis;
using Core.IBusiness.IProjectModule;
using Core.IBusiness.IProjectModule.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Threading;

namespace Core.Web
{
    /// <summary>
    /// API服务验证
    /// </summary>
    public class ApiVerificationAttribute : Attribute, IActionFilter
    {

        /// <summary>
        /// 是否计数
        /// </summary>
        private bool IsCount { get; set; }

        /// <summary>
        /// 服务类型
        /// </summary>
        private APIServiceEnum ApiServiceEnum { get; set; }

        /// <summary>
        /// Api用户服务
        /// </summary>
        private IProjectUserApiService iProjectUserApiService { get; set; }

        private IRedisHelper iRedisHelper { get; set; }

        /// <summary>
        /// 项目信息
        /// </summary>
        private ApiProjectInfo iProjectInfo { get; set; }

        /// <summary>
        /// Redis 限流器 HashName
        /// </summary>
        private string RedisHashKey { get; set; }


        public ApiVerificationAttribute(APIServiceEnum apiService)
        {
            // 处理服务类型
            this.ApiServiceEnum = apiService;

            // 处理服务是否需要计数
            switch (ApiServiceEnum)
            {
                case APIServiceEnum.SMS:
                case APIServiceEnum.Express:
                    this.IsCount = true;
                    break;

                case APIServiceEnum.BBS:
                case APIServiceEnum.Shop:
                case APIServiceEnum.Queue:
                    this.IsCount = false;
                    break;
            }

            // 获取API用户服务接口
            this.iProjectUserApiService = BuildServiceProvider.GetService<IProjectUserApiService>();

            this.iRedisHelper = BuildServiceProvider.GetService<IRedisHelper>();

            // 指定 14号仓库
            iRedisHelper.SpecifiedDatabaseNumber(14);
            

        }

        /// <summary>
        /// 从上下文构造需要的参数
        /// </summary>
        /// <param name="context">http 上下文</param>
        private void ContextInfo(ActionExecutingContext context)
        {
            this.iProjectInfo = (ApiProjectInfo)context.HttpContext.Items["ApiProjectInfo"] ?? new ApiProjectInfo();
            this.RedisHashKey = $"ApiVerification_{(int) ApiServiceEnum}_{this.iProjectInfo.Token}";
        }


        private int ApiAcquireLock(int balance, int r = 0)
        {
            int result = 0;

            // 查看节流器是否初始化
            this.iRedisHelper.AcquireLock(this.RedisHashKey, db =>
            {
                int.TryParse(db.StringGet(this.RedisHashKey), out int count);

                if (count == 0)
                {
                    db.StringSet(this.RedisHashKey, 1);
                    result = 1;
                }
                else if(balance <= count)
                {
                    result = 0;
                }
                else
                {
                    db.StringSet(this.RedisHashKey, count+1);
                    result = 1;
                }

            },
            () => {
                result = 2;
            },
            TimeSpan.FromSeconds(2));

            if (result == 2 && r <= 3)
            {
                r = r + 1;
                Thread.Sleep(1000);
                return this.ApiAcquireLock(result, r);
            }
            else
            {
                return result;
            }
        }


        /// <summary>
        /// Action执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {

            if (CoreStartupHelper.GetConfigValue("Service:ApiServiceVerification") != "True")
                return;

            this.ContextInfo(context);

            var result =
                this.iProjectUserApiService.IsApiAvailability(this.iProjectInfo.Key, (int) this.ApiServiceEnum);

            if (result.IsFinished)
            {
                return;
                if (result.Date.Key)
                {
                    // 有权限
                    var isOk = this.IsCount ? this.ApiAcquireLock(result.Date.Value) : 1;

                    switch (isOk)
                    {
                        case 1:
                            // 可以访问
                            break;
                        case 0:
                        case 2:
                            // 接口负载过大
                            context.Result = new ObjectResult(new ApiResult
                            {
                                code = CodeResult.INTERFACE_EXCEED_LOAD,
                                info = "接口负载过高"
                            });
                            return;
                    }
                }
                else
                {
                    // 无权限
                    context.Result = new ObjectResult(new ApiResult {
                        code = CodeResult.PERMISSION_NO_ACCESS,
                        info = "没有访问权限"
                    });
                    return;
                }
            }
            else
            {
                // 系统发送异常
                context.Result = new ObjectResult(new ApiResult
                {
                    code = CodeResult.INTERFACE_INNER_INVOKE_ERROR,
                    info = result.Discription
                });
                return;
            }

        }

        /// <summary>
        /// Action执行完成后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (CoreStartupHelper.GetConfigValue("Service:ApiServiceVerification") == "True")
            {
                try
                {
                    // 获取返回信息
                    var info = (IResult)((ObjectResult)context.Result).Value;

                    // 验证是否执行成功
                    if (info.code == CodeResult.SUCCESS)
                    {
                        // 并且需要计数
                        if (this.IsCount)
                        {
                            this.iProjectUserApiService.UseApiCount(this.iProjectInfo.UserKey, (int)this.ApiServiceEnum);
                        }
                    }

                    // 更新节流器在线用户数量
                    this.iRedisHelper.AcquireLock(this.RedisHashKey, db =>
                    {
                        int.TryParse(db.StringGet(this.RedisHashKey), out int count);

                        db.StringSet(this.RedisHashKey, count - 1);

                    });
                }
                catch (Exception e)
                {
                    // log
                }
            }

            var ApiBase = new ApiBaseControllerAttribute();

            ApiBase.ResultEncrypt(context);

        }


        
    }
}
